package com.zly;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zly.entity.DynamicJsonNode;
import com.zly.entity.DynamicSegment;
import com.zly.entity.Placeholder;
import com.zly.entity.block.DynamicBlock;
import com.zly.entity.block.OtherwiseBlock;
import com.zly.entity.block.WhenBlock;
import com.zly.entity.enums.Keyword;
import com.zly.entity.enums.SegmentType;
import com.zly.entity.parameter.DirectValueParameter;
import com.zly.entity.parameter.DynamicJsonParameter;
import com.zly.entity.parameter.FunctionReturnValueParameter;
import com.zly.functions.CommonFP;
import com.zly.functions.JsonOperateFP;
import com.zly.functions.FunctionProviderBase;

import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;

public class DynamicJson {
    //本类分析DynamicJson并处理成JsonNode

    private final ObjectMapper mapper;
    private final FunctionManager functionManager;
    private DynamicJsonNode processingDynamicJsonNode;
    private Map<Integer,String> paramIdValueMap;

    /* ---------- 以下为对外接口 ---------- */

    //构造
    public DynamicJson(){

        mapper = new ObjectMapper();
        functionManager = new FunctionManager();

        //注册内置函数
        functionManager.registerFunction(JsonOperateFP.class);
        functionManager.registerFunction(CommonFP.class);

    }

    //分析该DynamicJsonNode，返回分析后生成的JsonNode
    public JsonNode parse(JsonNode node) {

        if(node.has(Keyword.IS_DYNAMIC_JSON_NODE.getStrValue())){
            FunctionProviderBase.setCurNode(node);
            this.processingDynamicJsonNode = DJEntityFactory.produceDynamicJsonNode(node);
            return getResultJsonNode();
        }else{
            return node;
        }

    }

    //获取此DynamicJson的FunctionManager
    public FunctionManager getFunctionManager() {
        return functionManager;
    }

    /* ---------- 以上为对外接口 ---------- */

    //获取最终的结果JsonNode
    private JsonNode getResultJsonNode() {

        //计算参数的值
        calculateParameters();

        //获取最终需要返回的Content所在的Block
        DynamicBlock resultBlock = getResultBlock(processingDynamicJsonNode.getSegment());

        //返回替换了placeholder的BlockContent
        return getAppliedParametersJsonNode(resultBlock.getContentNode());

    }

    //从Segment中定位并返回应当返回的Block
    private DynamicBlock getResultBlock(DynamicSegment segment) {

        DynamicBlock resultBlock = null;{
            //若为选择型Segment
            if(segment.getSegmentType() == SegmentType.CHOOSE_SEGMENT){

                for(int i = 0; i < segment.getBlockArray().length; i++){
                    DynamicBlock curBlock = segment.getBlockArray()[i];
                    if(curBlock instanceof OtherwiseBlock){//若当前Block为OtherwiseBlock，立即返回
                        resultBlock = curBlock;
                        break;
                    }else if(curBlock instanceof WhenBlock whenBlock){
                        //处理WhenBlock的条件表达式字符串，替换其placeholder
                        String appliedParametersCondExpr = getAppliedParametersString(whenBlock.getCondExpr());
                        JsonNode condExprNode = null;{
                            try {
                                condExprNode = mapper.readTree(appliedParametersCondExpr);
                            } catch (JsonProcessingException e) {
                                throw new RuntimeException(e);
                            }
                        }
                        //若WhenBlock的条件表达式值为真，立即返回
                        if(DJUtils.isTruthy(condExprNode)){
                            resultBlock = curBlock;
                            break;
                        }

                    }
                }

            } else{//若Segment为如SINGLE_BLOCK_SEGMENT类型的仅包含单个Block的类型
                resultBlock = segment.getBlockArray()[0];
            }
        }

        return resultBlock;

    }

    //计算并将参数替换到placeholder
    private JsonNode getAppliedParametersJsonNode(JsonNode targetNode) {

        String resultJsonString = getAppliedParametersString(targetNode.toString());

        JsonNode resultNode = null;{
            try {
                resultNode = mapper.readTree(resultJsonString);
            } catch (JsonProcessingException e) {
                throw new RuntimeException(e);
            }
        }

        return resultNode;

    }

    //计算并将参数替换到placeholder
    private String getAppliedParametersString(String jsonString) {

        StringBuilder jsonStringBuilder = new StringBuilder(jsonString);
        int indexBias = 0;

        //查找所有符合placeholder格式的子串
        Matcher matcher = Placeholder.getLegalPattern().matcher(jsonString);
        while (matcher.find()) {

            int startIndex = matcher.start();
            int endIndex = matcher.end();

            //处理此placeholder，要注意处理后jsonStringBuilder的长度大概率会改变，因此需要维护indexBias来正确处理
            indexBias += processPlaceholderAtJsonString(jsonStringBuilder, startIndex + indexBias, endIndex + indexBias);

        }

        return jsonStringBuilder.toString();

    }

    //处理Json字符串(StringBuilder)中的一个placeholder的子串。返回处理前后StringBuilder的长度差
    private int processPlaceholderAtJsonString(StringBuilder jsonStringBuilder, int startIndex, int endIndex) {

        int originLength = jsonStringBuilder.length();

        String placeholderString = jsonStringBuilder.substring(startIndex, endIndex);
        Placeholder placeholder = new Placeholder(placeholderString);

        //检查该placeholder在字符串中是否已经被双引号包裹
        boolean wrappedInQuotesAlready;{
            wrappedInQuotesAlready = startIndex > 0 && jsonStringBuilder.charAt(startIndex - 1) == '"'
                    && endIndex < jsonStringBuilder.length() && jsonStringBuilder.charAt(endIndex) == '"';
        }

        //获取placeholder对应的参数
        DynamicJsonParameter parameter = matchParameter(placeholder);
        String stringValue = getParameterStringValue(parameter);
        if(stringValue == null){
            throw new RuntimeException("找不到参数对应的值:" + parameter);
        }

        //若为DirectValueParameter且为字符串类型，脱去参数的字符串值自带的双引号
        if(parameter instanceof DirectValueParameter && parameter.isOriginalStringType()){
            stringValue = stringValue.substring(1, stringValue.length() - 1);
        }

        //进行替换
        if(!parameter.isOriginalStringType() && wrappedInQuotesAlready){
            --startIndex;
            ++endIndex;
        }

        jsonStringBuilder.replace(startIndex, endIndex, stringValue);

        return jsonStringBuilder.length() - originLength;

    }

    //计算并保存参数的值
    private void calculateParameters(){

        paramIdValueMap = new HashMap<>();

        DynamicJsonParameter[] parameterArray = processingDynamicJsonNode.getParameterArray();
        //按顺序处理
        for(int i = 0; i < parameterArray.length; i++){

            DynamicJsonParameter parameter = parameterArray[i];
            processParameter(parameter);
            paramIdValueMap.put(parameter.getId(), evaluateStringValue(parameter));

        }

    }

    //若参数本身含有占位符，处理该参数
    private void processParameter(DynamicJsonParameter parameter){

        if(parameter instanceof DirectValueParameter dp){

            JsonNode valueNode = dp.getValueNode();
            if(valueNode.isTextual() || valueNode.isObject() || valueNode.isArray()){
                dp.setValueNode(getAppliedParametersJsonNode(dp.getValueNode()));
            }

        }else{

            FunctionReturnValueParameter fp = (FunctionReturnValueParameter) parameter;

            fp.setFunctionName(getAppliedParametersString(fp.getFunctionName()));

            Object[] args = fp.getFunctionArgs();
            for(int i = 0; i < args.length; i++){
                if(args[i] instanceof String){
                    args[i] = getAppliedParametersString((String) args[i]);
                }
            }

        }

    }

    //计算参数的字符串值
    private String evaluateStringValue(DynamicJsonParameter parameter) {
        if(parameter instanceof DirectValueParameter dp){
            return dp.getValueNode().toString();
        }else{

            FunctionReturnValueParameter fp = (FunctionReturnValueParameter) parameter;
            Object result = functionManager.executeFunction(fp);

            //FunctionReturnValueParameter只有计算完成返回值后才赋值其isOriginalStringType属性
            fp.setIsOriginalStringType(result instanceof String);

            return result.toString();

        }
    }

    //根据placeholder名称尝试匹配相应的参数
    private DynamicJsonParameter matchParameter(Placeholder placeholder){

        DynamicJsonParameter matchedParameter = null;{

            //尝试根据名称匹配对应参数
            for(DynamicJsonParameter parameter : processingDynamicJsonNode.getParameterArray()){
                if(placeholder.getName().equals(parameter.getParameterName())){
                    matchedParameter = parameter;
                    break;
                }
            }

            //若根据名称匹配未找到对应参数，且placeholder名称为数字字符串，尝试理解为数组下标并找到对应下标的参数
            if(matchedParameter == null){
                Integer index = Integer.parseInt(placeholder.getName());
                if(index != null && index < processingDynamicJsonNode.getParameterArray().length){
                    matchedParameter = processingDynamicJsonNode.getParameterArray()[index];
                }
            }

        }

        if(matchedParameter == null){
            throw new RuntimeException("无法找到" + placeholder + "对应的参数");
        }

        return matchedParameter;

    }

    //获取已计算完成并保存的参数字符串值
    private String getParameterStringValue(DynamicJsonParameter parameter){

        if(paramIdValueMap.containsKey(parameter.getId())){
            return paramIdValueMap.get(parameter.getId());
        }else{
            throw new RuntimeException("找不到该参数Id对应的参数值:" + parameter.getId());
        }

    }

}
